namespace Warehouse

open System
open System.Windows
open System.Collections.ObjectModel
open System.Data
open System.Net.Mail
open System.IO
open FSharp.Windows

type PurchaseOrderController(?repository) = 
    inherit Controller<PurchaseOrderEvents, PurchaseOrderModel>()

    let repository = defaultArg repository (new DataModel.Repository())
    let mutable purchaseOrderModified = false

    override this.InitModel model = 
        model.Items <- ObservableCollection()
        model.Last <- Nullable 20

    override this.Dispatcher = function
        | Search -> Sync this.Search
        | Edit -> Async this.Edit
        | Save -> Sync this.Save
        | PreviewLineItemDelete cancel -> Sync(this.PreviewLineItemDelete cancel)
        | DeleteLineItem -> Sync this.DeleteLineItem
        | AddLineItem -> Sync this.AddLineItem
        | SelectedPurchaseOrderChanged(previous, _) -> Sync(fun _ -> this.SelectedPurchaseOrderChanged previous)
        | LineItemModified columnName -> Sync(this.LineItemModified columnName)
        | Print -> Sync this.Print
        | EMail -> Sync this.EMail

    member this.Search model = 
        model.IsOperationInProgress <- true
        model.Items <- repository.PurchaseOrdersSearch(model.Filter, model.Last) |> Seq.map EntityModel.Load |> ObservableCollection.ofSeq 

        for x in model.Items do
            x.LineItems <- x.LineItems |> ObservableCollection.deleteEntityOnRemove repository

        model.IsOperationInProgress <- false

    member this.Edit model = 
        async {
            let mvc = Mvc(model.SelectedPurchaseOrder, PurchaseOrderDetailsView(), PurchaseOrderDetailsController repository)
            let! isSaved = mvc.StartWindow() 
            if not isSaved
            then
                model.SelectedPurchaseOrder.DiscardChanges()
        }

    member this.Save model = 
        let po = model.SelectedPurchaseOrder
        po.Validate()
        if po.IsValid
        then
            po.Save repository
            purchaseOrderModified <- false

    member this.PreviewLineItemDelete cancel model = 
        if this.DoYouReallyWantToDeleteLineItem model = MessageBoxResult.No 
        then 
            cancel()
        else
            model.SelectedPurchaseOrder.Compute()
            purchaseOrderModified <- true
        
    member private this.DoYouReallyWantToDeleteLineItem model = 
        let message = sprintf "Are you sure you want delete line item for product %s, quantity %i" model.SelectedLineItem.UPC.Product.ProductName.Name model.SelectedLineItem.Quantity
        MessageBox.Show(message, "Delete line item", MessageBoxButton.YesNo, MessageBoxImage.Warning, defaultResult = MessageBoxResult.No)

    member this.DeleteLineItem model = 
        if this.DoYouReallyWantToDeleteLineItem model = MessageBoxResult.Yes
        then 
            model.SelectedPurchaseOrder.LineItems.Remove(model.SelectedLineItem) |> ignore
            purchaseOrderModified <- true
        
    member this.AddLineItem model = 
        let x = Model.Create()
        if UpcSearchController.Mvc(x, repository).StartDialog()
        then 
            let upc = x.SelectedUPC.Entity
            let li : PurchaseOrderLineItemModel = Model.Create()
            li.UPC <- upc
            let product = upc.Product
            li.BasePrice <- product.ShopCost
            li.Commission <- product.VendorCommission model.SelectedPurchaseOrder.Vendor.Id
            li.Compute()
            model.SelectedPurchaseOrder.LineItems.Add li
            model.SelectedLineItem <- li

    member this.SelectedPurchaseOrderChanged previousPurchaseOrder = 
        if purchaseOrderModified 
        then
            if MessageBox.ActionConfirmed(sprintf "PurchaseOrder %i has been modified. Would you like to save it?" previousPurchaseOrder.Id, "Save changes") 
            then 
                previousPurchaseOrder.Validate()
                if previousPurchaseOrder.IsValid
                then
                    previousPurchaseOrder.Save repository
                else
                    MessageBox.Error(sprintf "Can not save PO #%i. Validation failed." previousPurchaseOrder.Id)
            else
                for deletedLineItem in repository.DeletedLineItems previousPurchaseOrder.Entity do
                    repository.Unchanged deletedLineItem
                previousPurchaseOrder.DiscardChanges()
                
            purchaseOrderModified <- false

    member this.LineItemModified columnName model =               
        purchaseOrderModified <- true  
        //if columnName = "%" then model.SelectedLineItem.DefaultPct <- false

    member private this.GetReportForm(model : PurchaseOrderModel) = 
        ReportForm.Create(
            reportName = "PurchaseOrder", 
            parameters = ["poId", string model.SelectedPurchaseOrder.Id]
        )

    member this.Print model = 
        this.GetReportForm(model).ShowDialog() |> ignore

    member this.EMail model =      
        let view = EMailView()
        let controller = EMailController repository
        let email : EMailModel  = Model.Create()
        let po = model.SelectedPurchaseOrder
        let vendor = po.Vendor
        email.Recipient <- vendor.EMail
        email.Subject <- sprintf "Attn: %s. Purchase order #%i" vendor.Attn po.Id
        model.IsOperationInProgress <- true
        let pdf = this.GetReportForm(model).GetPDF()
        email.Attachment <- 
            new Attachment(
                contentStream = new MemoryStream(pdf), 
                name = sprintf "PO#%i.%s.pdf" po.Id po.Vendor.CompanyName)
        model.IsOperationInProgress <- false
        Mvc(email, view, controller).StartDialog() |> ignore

